#!/usr/bin/python
import socket
import threading
import time
import base64
import md5
import hmac
import fileinput
import string
import re
import sys
import os
import popen2
import signal
import getopt
import ConfigParser
import MySQLdb
import math
from syslog import *
from time import strftime

__version__='0.4'

addr="239.192.1.100"
port=5000
arch_conf="/etc/prorc/balanC.conf"
arch_pid="/var/run/prorc.pid"
debug=0
estadistica=0
NOMBRE_HOST=socket.gethostname()

"""Diccionario con las variables necesarias en el archivo de configuracion """
salida={'Default': {\
			    'ip_servers_habilitados': '192.168.2.84,192.168.2.85',\
			    'ip_multicast': '239.192.1.100',\
			    'intervalo_estado_carga': '40',\
			    'intervalo_envio': '10',\
			    'llave': '"SeCreT"',\
			    'ip_multicast_ttl': '2',\
			    'intervalo_lista': '20',\
			    'puerto': '5000',\
			    'intervalo_estado_servicios': '40',\
			    'pesoavg': '1',\
			    'pesocpuh': '1',\
			    'pesomem': '1',\
			    'redbw': '20000000',\
			    'pesocpu': '1',\
			    'pesoclientes': '1',\
			    'pesored': '1',\
			    'pesoserver': '1',\
			    'pesoswap': '1',\
			    'comandos_shell': '/usr/local/bin/check_ssh -H localhost, /usr/local/bin/check_rpc -H localhost -C nfs -c 3, /usr/local/bin/check_rpc -H localhost -C portmapper -c 2 , /usr/local/bin/check_rpc -H localhost -C nlockmgr -c 3, /usr/local/bin/check_rpc -H localhost -C mountd -c 3, /usr/local/bin/check_rpc -H localhost -C status -c 1, /usr/local/bin/check_nro_nfsd',\
			    'comandos_shell_timeout' : '5',\
			    'algoritmo_elegido': 'rr_pesos_dinamicos_1',\
			    'algoritmo_escalar': '1',\
			    'clientetimeout': '5',\
			    'puerto_server': '1703',\
			    'log_facility': 'LOG_LOCAL7',\
			    'log_opt': 'LOG_PID',\
			    'log_nombre': "'ProRC'",\
			    'log_mascara': '255',\
			    'estadistica_motor_db': 'mysql',\
			    'estadistica_server_db': 'localhost',\
			    'estadistica_serverport_db': '3306',\
			    'estadistica_name_db': 'ProRC',\
			    'estadistica_tabla_db': 'estadistica',\
			    'estadistica_user_db': 'ProRC',\
			    'estadistica_pass_db': 'ProRC',\
			    'cpupower': '1',\
			    'maxavg': 4,\
			    'maxclientes': 45\
					},NOMBRE_HOST: {\
			    'cpupower': '1',\
			    'maxavg': 4,\
			    'maxclientes': 45\
	}}

# Si no existe el archivo de configuracion crea un archivo modelo basado en el diccionario '*salida*'
# y posteriormente debe volver a correp el programa
def crea_configuracion():
	global salida
	global arch_conf
	try:
		dirname=os.path.dirname(arch_conf)
		os.makedirs(dirname)
	except OSError:
		print 'Ya existe el directorio de configuracion'

	conf=ConfigParser.ConfigParser()
	for i in salida.keys():
		conf.add_section(i)
		syslog(LOG_DEBUG,"keys :"+str(i))
		for k in salida[i].keys():
			syslog(LOG_DEBUG,"sub key:"+str( k)+" =  "+str( salida[i][k]))
			conf.set(i,k,salida[i][k])
	fp=open(arch_conf,'w')
	conf.write(fp)


# Parsea el archivo de configuracion y lo almacena en el diccionario *'salida'*
def leer_configuracion():
	global arch_conf
	global salida
	config=ConfigParser.ConfigParser()
	config.read(arch_conf)
	for i in  config.sections():
		syslog(LOG_INFO,"\nSeccion : ["+str(i)+"]")
		for v in config.options(i):
			if salida.has_key(i) :
			    salida[i][v]=config.get(i,v)
			else:    
			    salida[i]={v : config.get(i,v)}
			syslog(LOG_INFO,"Opcion:"+str( v)+"="+str( salida[i][v]))


# La clase Estadistica registra informacion en una base *mysql* para realizar estadisticas 
# desde donde botea cada cliente y que servidor fue designado.
# Si se inicia el programa no se puede conectarse se continua si estadistica.
# Cada cliente que se atiende se inserta un registro con la siguiente informacion
# (horat, origent, puertoorigent, destinot, puertodestinot,servidort, okt, observacionest,cursor.rowcount)
#
class Estadistica:
	"""Clase Estadistica"""
        def __init__(self):
		global estadistica
		global configuracion
		if configuracion.estadistica_motor_db=='mysql':
			try:
				self.conn = MySQLdb.connect (host = str(configuracion.estadistica_server_db), port=int(configuracion.estadistica_serverport_db) ,user = str(configuracion.estadistica_user_db) ,passwd = str(configuracion.estadistica_pass_db), db = str(configuracion.estadistica_name_db))
				estadistica=1
				syslog(LOG_INFO,"Db_Estadistica -  Conn : Ok .")
						
			except MySQLdb.Error, e:
				syslog(LOG_INFO,"Estadistica -  init Conn : Error %d: %s - Continua SIN ESTADISTICA !!!" % (e.args[0], e.args[1]))
				estadistica=0

	def db_registro(self, origent, puertoorigent, destinot, puertodestinot, servidort, okt, observacionest='', horat=strftime("%Y-%m-%d %H:%M:%S")):
		global estadistica
		if estadistica==1 :
			try:
				cursor = self.conn.cursor ()
				cursor.execute ("""INSERT INTO estadisticas (hora, origen, puertoorigen, destino, puertodestino, servidor, ok, observaciones) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)""",(horat, origent, puertoorigent, destinot, puertodestinot,servidort, okt, observacionest))
				cursor.close()
				syslog(LOG_DEBUG,"Estadistica -  Db_Registro : se registro  %s, %s, %s, %s, %s, %s, %s, %s - Nro de columnas insertadas: %d " % (horat, origent, puertoorigent, destinot, puertodestinot,servidort, okt, observacionest,cursor.rowcount))
				
			except MySQLdb.Error, e:
				syslog(LOG_INFO,"Estadistica -  Db_Registro : Error %d: %s - Insertando registro !!!" % (e.args[0], e.args[1]))
				

# Al instanciar esta clase se obtiene un objeto con todas las variables de configuracion posibles de colocar en el Archivo de configuracion.
# 
class Configuracion:
	"""Clase Configuracion"""
	def __init__(self):
		self.intervalo_estado_servicios=40
		self.intervalo_estado_carga=40
		self.intervalo_envio=10
		self.intervalo_lista=20
		self.ip_multicast="239.192.1.100"
		self.ip_multicast_ttl=2
		self.ip_servers_habilitados=('192.167.77.2','192.167.77.1')
		self.puerto=5000
		self.llave="SeCreT"
		self.clientetimeout=5
		self.puerto_server=1703
		self.cpupower=1
		self.maxavg=4
		self.redbw=20000000
		self.maxclientes=45
		self.pesoserver=1
		self.pesomem=1
		self.pesoswap=1
		self.pesocpu=1
		self.pesocpuh=1
		self.pesoavg=1
		self.pesored=1
		self.pesoclientes=1
		self.log_facility=LOG_LOCAL7
		self.log_nombre='ProRC'
		self.log_opt=LOG_PID
		self.log_mascara=255
		self.estadistica_motor_db='mysql'
		self.estadistica_server_db='localhost'
		self.estadistica_serverport_db=3306
		self.estadistica_name_db='ProRC'
		self.estadistica_tabla_db='estadistica'
		self.estadistica_user_db='ProRC'
		self.estadistica_pass_db='ProRC'
		self.comandos_shell=('/usr/local/bin/comando1','/usr/local/bin/comando2','/usr/local/bin/comando3')
		self.comandos_shell_timeout=5
		self.algoritmo_elegido='rr_pesos_dinamicos_1'
		self.algoritmo_escalar=1

	def mostrar(self):
		cadena="\nConfiguracin Actual :\n"
                for k in (self.__dict__).keys():
			cadena += " Opcion:" + str(k) + "=" + str(self.__dict__[k]) + "\n"
			
                return cadena
	
	def configurar(self,diccionario):
			print '------------->' + 'Default' + '<--------------'
			for k in diccionario['Default'].keys():
				if (self.__dict__).has_key(k):
				    print "clave :", k, " viejo :",self.__dict__[k], " nuevo:", diccionario['Default'][k]
				    if k== 'ip_servers_habilitados' :
				    	self.__dict__[k]=diccionario['Default'][k].split(',')
				    elif k== 'comandos_shell' :
				    	self.__dict__[k]=diccionario['Default'][k].split(',')
				    else :
					self.__dict__[k]=diccionario['Default'][k]
			print '------------->' + NOMBRE_HOST + '<--------------'
			for j in diccionario[NOMBRE_HOST].keys():
				if (self.__dict__).has_key(k):
				    print "clave :", j, " viejo :",self.__dict__[j], " nuevo:", diccionario[NOMBRE_HOST][j]
				    if k== 'ip_servers_habilitados' :
				    	self.__dict__[j]=diccionario[NOMBRE_HOST][j].split(',')
				    elif k== 'comandos_shell' :
				    	self.__dict__[j]=diccionario[NOMBRE_HOST][j].split(',')
				    else :
					self.__dict__[j]=diccionario[NOMBRE_HOST][j]

#
# La clase Estado es utilizada para parsear la informacion recibida de los otros servidores
# 
class Estado:
	"""Clase Estado"""
        def __init__(self):
                self.lock = threading.Lock()
                self.servicios=0
                self.carga=0
		self.timestamp=0

        def set_servicios(self,valor):
                self.lock.acquire()
                self.servicios=valor
                self.lock.release()


        def set_carga(self,valor):
                self.lock.acquire()
                self.carga=valor
                self.lock.release()

	def parse_estado(self,cadena):
		temp=cadena.split("|||")
		if len(temp) > 1 :
			self.lock.acquire()
			self.servicios=temp[0]
			self.carga=float(temp[1])
			self.timestamp=temp[2]
			self.lock.release()
		return self

# La clase Servicios_chk hereda de la clase Thread y al instanciarse, este hilo es el encargado de verificar 
# a intervalos regulares el estado de los servicios.
# Los servicios a chequear conjuntamente con el intervalo de tiempo son determinados en el archivo de configuracion.
# Se utiliza la convencion de los scrpits de nagios, es decir si el scrpit que chequea un servicio retorna 0
# el servicio se encuentra Ok, si retorna 1 es warning y 2 es un error critico
# 
class Servicios_chk(threading.Thread):
	"""Clase Servicios_chk"""
        def __init__(self):
                threading.Thread.__init__(self)
                self.fin=0
		self.pid=''
        def termina(self):
                self.fin=1
                
        def run(self):
                global estado
                global configuracion
                while self.fin==0 :
			estado.set_servicios(0)
			ok_comandos=0
			for com in configuracion.comandos_shell :
                       	 	try :
                			std=popen2.Popen3(com,True)
                			tiempo=0
					while tiempo <= int(configuracion.comandos_shell_timeout) :
						poll_std=std.poll()
						if poll_std != -1 :
							break
						time.sleep(1)
						tiempo += 1
					if poll_std==0 :
						std_salida=std.fromchild.read()
						ok_comandos += 1
						syslog(LOG_INFO,"Servicios_chk --  Run : Ok al ejecutar :: " + com  +" StdOut : "+ std_salida )
					elif poll_std > 0 :
						syslog(LOG_ERR,"Servicios_chk --  Run : Error al ejecutar :: " + com  +" StdOut : "+ std.fromchild.read() + " StdErr" + std.childerr.read())
					else :
						syslog(LOG_ERR,"Servicios_chk --  Run :  Timeout al ejecutar :: " + com) 
					std.fromchild.close()
					std.childerr.close()
					std.tochild.close()
					
				except Exception, detail :
                			print "Excep err : ", str(detail)
                			syslog(LOG_ERR,"Servicios_chk --  Run  : Excepcion ejecutar comandos_shell :: " + str(detail))
			if len(configuracion.comandos_shell) == ok_comandos :
				estado.set_servicios(1)
                        	syslog(LOG_INFO,"Servicios_check - Valor :" + str(estado.servicios))
			else: 
				estado.set_servicios(0)
				syslog(LOG_INFO,"Servicios_check - Valor Error :" + str(ok_comandos) + " :: Nro de Servicios :" + str(len(configuracion.comandos_shell)))
                        time.sleep(int(configuracion.intervalo_estado_servicios))
	
		
# La clase Carga_chk hereda de la clase Thread y, al instanciarse, este hilo es el encargado de comprobar
# el estado carga del servidor. Esta clase realiza la llamada a un algoritmo de calculo
# (elegido en el archivo de configuracion). Por defecto se utiliza el Algoritmo2 para
# determinar la disponibilidad del servidor.
# 
class Carga_chk(threading.Thread):
	"""Clase Carga_chk"""
        def __init__(self):
                threading.Thread.__init__(self)
                self.fin=0
        def termina(self):
                self.fin=1
                
        def run(self):
                global estado
                global configuracion
                while self.fin==0 :
			try:
				if configuracion.algoritmo_elegido == 'algoritmo1' :
		                        cargac=float(algoritmo1())
				elif (configuracion.algoritmo_elegido == 'algoritmo2'):
	                	        cargac=float(algoritmo2())
				elif (configuracion.algoritmo_elegido == 'algoritmo3') :
		                        cargac=float(algoritmo3())
				else: 
				 	print 'No eligio correctamente un algoritmo se opta por algoritmo2'
	                        	cargac=float(algoritmo2())
	
        	                estado.set_carga(cargac)
                	        syslog(LOG_INFO,"Carga_check -  Valor :" + str(estado.carga))
                        except Exception, detail :
                                print "Excep err : ", str(detail)
                                syslog(LOG_ERR,"Carga_chk --  Run  : Excepcion :: " + str(detail))
			time.sleep(int(configuracion.intervalo_estado_carga))

# La clase Lista_top hereda de la clase Thread y al instanciarse, el hilo es el encargado de armar
# una tabla con los servidores en orden de preferencia.
# La tabla tiene en cuenta la disponibilidad de cada servidor, y la cantidad de pedidos atentidos.
# 
class Lista_top(threading.Thread):
	"""Clase Lista_top"""
        def __init__(self):
		threading.Thread.__init__(self)
		self.tabla_lck = threading.Lock()	#Lock para tabla 
		self.tabla={}				#Tabla es un diccionario que acumula el estado de los servidores del tipo servidor : estado
		self.listatop_lck=threading.Lock()
		self.listatop=[]
		self.listaordenada_lck=threading.Lock()
		self.listaordenada=[]
		self.listapedidos_lck=threading.Lock()
		self.listapedidos={}
		self.nroorden=0
		self.rrobin=0
		self.fin=0
	
	def run(self):
                global configuracion
		while self.fin==0 :
			try : 
				time.sleep(int(configuracion.intervalo_lista))
				syslog(LOG_DEBUG,"Lista_top  -- Se ordena la lista ...-")	
				self.arma_lista_ordenada()
				self.tabla_lck.acquire()
				self.tabla.clear()
				self.tabla_lck.release()
				syslog(LOG_INFO,"Lista_top -- Se limpia ls lista ...")
				syslog(LOG_DEBUG,"Lista_top --  Lista Ordenada :"+ str(self.listaordenada))
				syslog(LOG_DEBUG,"Lista_top --  Lista Top:"+ str(self.listatop))
			except Exception, detail :
				syslog(LOG_ERR ,"Lista_top --  Excepcion hilo Lista Top : " + str(detail))
				
		
	def termina(self):
                self.fin=1
		
	def agrega_lista(self,estado,servidor):
		self.tabla_lck.acquire()
		if self.tabla.has_key(servidor):
			if self.tabla[servidor][2] < float(estado.timestamp) :
				syslog(LOG_DEBUG,"Lista_top --  Agrega lista : TIMESTAMP mayor :" + str(servidor)+ "::" + str(self.tabla[servidor][2]) +" - " + str(float(estado.timestamp)))
			else :
				syslog(LOG_DEBUG,"Lista_top --  Agrega lista : ATAQUE !!! TIMESTAMP IGUAL :" + str(servidor)+ "::" + str(self.tabla[servidor][2]) +" - " + str(float(estado.timestamp)))
		else:
			syslog(LOG_INFO,"Lista_top --  Agrega lista : No existe TIMESTAMP :" +str(servidor) + "::" + str(float(estado.timestamp))) 
		self.tabla[servidor]=(int(estado.servicios),float(estado.carga),float(estado.timestamp))
		self.tabla_lck.release()
	
	def ordena_lista(self,listatemp):
		syslog(LOG_INFO,"Lista_top --  ordena lista  ...")
		listasal=[]
		try :
			if len(listatemp) > 0:
				listasal=[(v,k) for k, v in listatemp]
				listasal.sort()
				listasal.reverse()
				listasal=[(k,v) for v, k in listasal]
			
		except Exception, detail :	
                	syslog(LOG_ERR,"Lista_top --  ordena lista : Excepcion arma lista ordenada :: " + str(detail)) 
		return 	listasal
	
	def ajusta_pedidos(self,listatemp):
		if len(listatemp) > 0:
			self.listapedidos_lck.acquire()
			try :
					
				for a,b in listatemp :
					if self.listapedidos.has_key(a) :
	             				x=self.listapedidos[a]
						syslog(LOG_DEBUG,"Lista_top --  Arma lista ordenada : Lista Pedidos ::" + str(a) + " Valor:"+ str(self.listapedidos[a]))
					else:
	             				x=0
	             				syslog(LOG_DEBUG,"Lista_top --  Arma lista ordenada : Lista Pedidos ::" + str(a) + " no Existe")
	     				self.listaordenada_lck.acquire()
					self.listaordenada.append((a,(b[0],(b[1]-x),b[2])))
					self.listaordenada_lck.release()
			except Exception, detail :	
                		syslog(LOG_ERR,"Lista_top --  ajusta pedidos : Excepcion ajusta pedidos :: " + str(detail)) 
			self.listapedidos_lck.release()
				
	def arma_lista_ordenada(self):
		syslog(LOG_INFO,"Lista_top --  Arma lista ordenada ...")
		listatemp=[]
		self.listatop_lck.acquire()
		self.listatop=[]
		self.listatop_lck.release()
		self.listaordenada_lck.acquire()
		self.listaordenada=[]
		self.listaordenada_lck.release()
		
		if len(self.tabla) > 0:	
			self.tabla_lck.acquire()
			try :
				listatemp=self.ordena_lista(self.tabla.items())
				self.ajusta_pedidos(listatemp)
				self.listaordenada_lck.acquire()
				self.listaordenada=self.ordena_lista(self.listaordenada)
				self.listaordenada_lck.release()
				syslog(LOG_INFO,"Lista_top --  Arma lista ordenada : ARMO LISTAS de NUEVO")
				syslog(LOG_DEBUG,"Lista_top --  Arma lista ordenada : Lista top ::" + str(self.listatop))
				syslog(LOG_DEBUG,"Lista_top --  Arma lista ordenada : Lista ordenada ::" + str(self.listaordenada))
				syslog(LOG_DEBUG,"Lista_top --  Arma lista ordenada : Lista Pedidos ::" + str(self.listapedidos))
			
			except Exception, detail :	
                		syslog(LOG_ERR,"Lista_top --  Arma lista ordenada : Excepcion arma lista ordenada :: " + str(detail)) 
			self.tabla_lck.release()
		self.listatop_lck.acquire()
		self.listatop=listatemp
		self.listatop_lck.release()
	
	def saca_de_lista(self):
		ip_server=""
		syslog(LOG_INFO,"Lista_top --  Saca de lista ...")
		
		if ((len(self.listatop) > 0) and (len(self.listaordenada) > 0)) :
		    	self.listaordenada_lck.acquire()
			try :
				if  (self.listaordenada[0][1][1] < 0.1) :
			    		if self.nroorden > 0 :
						syslog(LOG_INFO,"Lista_top --  Saca de lista : Lista Ordenada < 0,1 y Norden > 0 ")
						syslog(LOG_DEBUG,"Lista_top --  Saca de lista : Lista top Antes ::" + str(self.listatop))
						syslog(LOG_DEBUG,"Lista_top --  Saca de lista : Lista ordenada Antes ::" + str(self.listaordenada))
						syslog(LOG_DEBUG,"Lista_top --  Saca de lista : Nro de veces ::" + str(self.nroorden))
						syslog(LOG_DEBUG,"Lista_top --  Saca de Lista : listaPedidos : "+ str(self.listapedidos) )
						self.listapedidos_lck.acquire()
						self.listapedidos.clear()
						self.listapedidos_lck.release()
						syslog(LOG_DEBUG,"Lista_top --  Saca de Lista : Reinicio listaPedidos : " )
			    			self.listaordenada= self.listatop
						self.nroorden=0
			    			self.rrobin=0
						syslog(LOG_INFO,"Lista_top --  Saca de lista : Despues de REINICIO de LISTAS ")
						syslog(LOG_DEBUG,"Lista_top --  Saca de lista : Lista top Despues ::" + str(self.listatop))
						syslog(LOG_DEBUG,"Lista_top --  Saca de lista : Lista ordenada Despues ::" + str(self.listaordenada))
						syslog(LOG_DEBUG,"Lista_top --  Saca de lista : Nro de veces ::" + str(self.nroorden))
			    		
					else:
						self.rrobin=1
						self.listaordenada[0]=( self.listaordenada[0][0], ( self.listaordenada[0][1][0], self.listaordenada[0][1][1]-0.1, self.listaordenada[0][1][2]))
						if self.listaordenada[0][1][1] < 0 :
							self.listapedidos_lck.acquire()
							self.listapedidos.clear()
							self.listapedidos_lck.release()
							syslog(LOG_DEBUG,"Lista_top --Saca de lista :  Reinicio listaPedidos : " )
						if self.listapedidos.has_key(self.listaordenada[0][0]):
							self.listapedidos[self.listaordenada[0][0]] += 0.1
							syslog(LOG_DEBUG,"Lista_top -- Saca de lista : Saca listaPedidos : "+str(self.listaordenada[0][0]) + ":: Valor :" + str(self.listapedidos[self.listaordenada[0][0]] ))
						else:
					 		self.listapedidos[self.listaordenada[0][0]] = 0.1
							syslog(LOG_DEBUG,"Lista_top -- Saca de lista : Saca listaPedidos : "+str(self.listaordenada[0][0]) + ":: Valor :" + str(self.listapedidos[self.listaordenada[0][0]] ))
						syslog(LOG_DEBUG,"Lista_top --  Saca de lista : Entra en RRobin :: Nro de veces ::" + str(self.nroorden))
				else:
					self.listaordenada[0]=( self.listaordenada[0][0], ( self.listaordenada[0][1][0], self.listaordenada[0][1][1]-0.1, self.listaordenada[0][1][2]))
					self.nroorden=self.nroorden+1
					if self.listapedidos.has_key(self.listaordenada[0][0]):
						self.listapedidos[self.listaordenada[0][0]] += 0.1
						syslog(LOG_DEBUG,"Lista_top -- Saca de lista : Saca listaPedidos : "+str(self.listaordenada[0][0]) + ":: Valor :" + str(self.listapedidos[self.listaordenada[0][0]] ))
					else:
						self.listapedidos[self.listaordenada[0][0]] = 0.1
					 	syslog(LOG_DEBUG,"Lista_top -- Saca de lista :  Saca listaPedidos : "+str(self.listaordenada[0][0]) + ":: Valor :" + str(self.listapedidos[self.listaordenada[0][0]] ))
				ip_server=self.listaordenada[0][0][0]
				self.listaordenada=self.ordena_lista(self.listaordenada)
				
			except Exception, detail :	
                		syslog(LOG_ERR,"Lista_top -- Saca de lista : Excepcion Saca de lista :: " + str(detail)) 
			self.listaordenada_lck.release()
		syslog(LOG_DEBUG,"Lista_top --  Saca de lista : Ip server ::" +str(ip_server))
		return ip_server


# La clase Estado_net hereda de la clase Thread, y al instanciarse el hilo es el encargado de escuchar
# por multicast el estado de los otros servidores
# 
class Estado_net(threading.Thread):
	"""Clase Estado_net"""
	def __init__(self):
		threading.Thread.__init__(self)
		self.fin=0
		global configuracion
		self.intf = socket.gethostbyname(socket.gethostname())
		self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
		self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, int(configuracion.ip_multicast_ttl))
		self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf))
		self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(str(configuracion.ip_multicast)) + socket.inet_aton(intf))
		try: 
			####### ojo quitar ip###
			#self.sock.bind((self.intf, int(configuracion.puerto)))
			self.sock.bind(('', int(configuracion.puerto)))
		except Exception, detail :
			syslog(LOG_ERR,"Estado_net --  Excepcion: " + str(detail))
			self.sock.close()
			sys.exit(1)

	def termina(self):
		self.fin=1
		self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_DROP_MEMBERSHIP, socket.inet_aton(str(configuracion.ip_multicast)) + socket.inet_aton(intf))
		self.sock.close()
	def run(self):
		estadotmp=Estado()
		global configuracion
		global lista
		while self.fin==0 :
			try : 
				data, sender_addr = self.sock.recvfrom(1024)
				long_data=len(data)
				ippuerto=sender_addr[0]
				if ((len(configuracion.ip_servers_habilitados) == 0) or (ippuerto in configuracion.ip_servers_habilitados)):
					if long_data > 32 :
						try :
							data_chksum=data[long_data-32:long_data]
							data_encode=data[0:long_data-32]
							#paquete_chksum=md5.new(data_encode + str(configuracion.llave))
							paquete_chksum=hmac.new((str(configuracion.llave) + str(ippuerto)) ,data_encode )
							syslog(LOG_DEBUG,"Estado_net --  Paquete Recibido ::  De:" + str(sender_addr) + " Datos:" + data_encode + " chk:" + data_chksum)	
							if data_chksum == str(paquete_chksum.hexdigest()):
								paquete_str=base64.decodestring(data_encode)
								syslog(LOG_DEBUG,"Estado_net --  Paquete Recibido ::  De:" + str(sender_addr) + " datos decodificados:"+ str(paquete_str) + " checksum:" + data_chksum)
								lista.agrega_lista(estadotmp.parse_estado(paquete_str),sender_addr)
							else:
								syslog(LOG_INFO,"Estado_net --  Paquete Recibido ::  De:" + str(sender_addr) + " Recibido FALSO " )
						except Exception, detail :
							syslog(LOG_ERR,"Estado_net -- Excepcion Paquete Recibido - Decodificado ::  De:" + str(sender_addr) + " Datos:" + data_encode + " chk:" + data_chksum + " Decodificado:"+ str(paquete_str) + " Longitud:" + str(long_data) + " Exception :" + str(detail))
				else:
					syslog(LOG_INFO,"Estado_net --  Paquete Recibido ::  De:" + str(sender_addr) + " Equipo NO HABILITADO !!! ")
			except Exception, detail :
				syslog(LOG_ERR,"Estado_net -- Excepcion Paquete Recibido ::  De:" + str(sender_addr) + " Datos:" + str(data) + " Longitud:" + str(long_data) + " Exception :" + str(detail))
				##sys.exit(1)



# La clase Estado_net_cliente hereda de la clase Thread, y al instanciarse el hilo es el encargado de enviar
# por multicast la disponibilidad del propio servidor
# 
class Estado_net_cliente(threading.Thread):
	"""Clase Estado_net_cliente"""
        def __init__(self):
                threading.Thread.__init__(self)
                self.fin=0
                global configuracion
                self.intf = socket.gethostbyname(socket.gethostname())
                self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
                self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, int(configuracion.ip_multicast_ttl))
                self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf))
                self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(str(configuracion.ip_multicast)) + socket.inet_aton(intf))
        def termina(self):
                self.fin=1
                self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_DROP_MEMBERSHIP, socket.inet_aton(str(configuracion.ip_multicast)) + socket.inet_aton(intf))
                self.sock.close()
        def run(self):
                global estado
                global configuracion
                while self.fin==0 :
                        time.sleep(int(configuracion.intervalo_envio))
                        if estado.servicios == 1 :
                                time_stamp=time.time()
                                paquete_str=str(estado.servicios) + "|||" + str(estado.carga)  + "|||" +str(time_stamp)
                                paquete_codec=base64.encodestring(paquete_str)
                                #paquete_chksum=md5.new(paquete_codec + str(configuracion.llave))
				paquete_chksum=hmac.new((str(configuracion.llave)+ str(intf)),paquete_codec)
				syslog(LOG_INFO,"Estado_net_cliente --  Paquete enviando ..")
				syslog(LOG_DEBUG,"Estado_net_cliente --  Paquete enviando :: Paquete codec:" + paquete_codec + " chk :" + str(paquete_chksum.hexdigest()) + " paquete str : "+paquete_str)
                                paquete=paquete_codec + str(paquete_chksum.hexdigest())
                                self.sock.sendto(paquete, (str(configuracion.ip_multicast), int(configuracion.puerto)))
                                syslog(LOG_DEBUG,"Estado_net_cliente --  Paquete enviado desde :" + intf)
                        else:
                                syslog(LOG_INFO,"Estado_net_cliente --  NO ENVIA Paquete ")
				syslog(LOG_DEBUG,"Estado_net_cliente --  NO ENVIA Paquete:: Estado servicios:" + str(estado.servicios)+ " Desde:"+ intf )
                                
# La clase Servidor_net hereda de la clase Thread, y encargada de atender a los clientes en un socket TCP
# Se lanza un hilo por cada cliente que se conecta
# 
class Servidor_net(threading.Thread):
	"""Clase Servidor_net"""
        def __init__(self,socketc,ap,sockii):
                threading.Thread.__init__(self)
                #threading.Timer(10)
		self.socket_cliente=socketc
		self.app=ap
		self.socki=sockii
	
	def termina(self):
                self.fin=1
                self.socket_cliente.close()
                		
	def run(self):
                global configuracion
                global lista
		global locklista
		global lista_conectados
		global estadistica
		global regestadistica
		global intf
		ttm=""
		try :
			self.socket_cliente.settimeout(int(configuracion.clientetimeout))
			#self.socket_cliente.send("Conectado..\n")
			rem_comando=self.socket_cliente.recv(1024)
			rem_comando=string.strip(rem_comando)
			ttm='0'
			ok=False
			syslog(LOG_DEBUG,"Servidor_net --  Conexion de:" + str(self.app))
			syslog(LOG_DEBUG,"Servidor_net --  Conexion de:" + str(self.app) + " recibi el comando : " + str(rem_comando))
			if rem_comando=="ip" :
				ttm=lista.saca_de_lista()
				syslog(LOG_DEBUG,"Servidor_net --  Conexion de:" + str(self.app) + "Comando Aceptado se asigna server: " +  str(ttm))
				self.socket_cliente.send(string.strip(str(ttm))+"\n")
				#self.socket_cliente.send((str(lista.tabla))+"\n")
				ok=True
			self.socket_cliente.close()
			if estadistica==1 :
				regestadistica.db_registro(self.app[0], self.app[1], str(intf),configuracion.puerto_server, ttm, ok,rem_comando,strftime("%Y-%m-%d %H:%M:%S"))
				syslog(LOG_INFO,"Servidor_net --  Regestadistica : Registrando ..")
			#print " Sockets :",self.app, intf
			
		except Exception, detail :
			syslog(LOG_ERR,"Servidor_net --  Excepcion: " + str(detail))
			self.socket_cliente.close()
			sys.exit(1)
		try :
			locklista.acquire()
			lista_conectados.remove((self.app,self.socki,self))
			locklista.release()
		
		except Exception, detail :
			syslog(LOG_ERR,"Servidor_net borra de lista --  Excepcion: " + str(detail))
			self.socket_cliente.close()
			sys.exit(1)
		
# -------------------------------------------------------------------------
# Esta funcion parsea el /proc y retorna una Tupla
# (mas precisamente una lista de python) con los los valores normalizados
# de carga '[MemN,SwapN,CPUn,CPUHn,CPUAVGn,REDn,UsuariosN]'.
# Donde: 
#
# o **MEMn:** Utlizacion de memoria MemN=(MemMax-MemUsada)/MemMax = MemLibre/MemMax
#
# o **SWn:** Utilizacion del Swap
#
# o **CPUn:** CPU instantaneo, carga de CPU en el ultimo segundo
#
# o **CPUHn:** historico, uso promedio de CPU desde que se encendio el equipo
#
# o **CPUAVGn:** uso promedio de CPU en los ultimos 5 min, como lo muestra el top
#
# o **REDn:** Utlizacion de la red
#
# o **USUARIOSn:** Cantidad de usuarios conectados por ssh
def parsea_proc(): 
	""" Funcion parsea_proc():"""
	global configuracion
	dic={}
	intf=socket.gethostbyname(socket.gethostname())
	intfl=string.split(intf,".")
	patron = re.compile (r' +|: *')
	octstr=""
	for val in intfl:
		oct=string.split(str(hex(int(val))),"0x")
		if len(oct[1])==1:
			octstr=("0"+oct[1]).upper() + octstr 
		else:
			octstr=oct[1].upper() + octstr 
	octstr=octstr+":0016"    
	
	#> ------ memoria ----------------->
	for line in fileinput.input('/proc/meminfo'):
		if re.search("MemTotal|Buffers|Cached|SwapTotal|SwapFree|MemFree",line) :
			lista=string.split(line)
			dic[lista[0]]=lista[1]
	fileinput.close()
	MemLibre=float((float(dic["MemFree:"])+float(dic["Buffers:"])+float(dic["Cached:"])))
	MemMax=float(dic["MemTotal:"])
	MemN=MemLibre/MemMax
	print """----MemLibre,MemMax,MemN------"""
	print MemLibre,MemMax,MemN
	syslog(LOG_DEBUG,"Parsea_proc --  Valor MemN:"+ str(float(MemN)))
	#< ------ memoria -----------------<
		
	#> --------  Swap   --------------->
	SwapN=float(float(dic["SwapFree:"])/float(dic["SwapTotal:"]))
	syslog(LOG_DEBUG,"Parsea_proc --  Valor SwapN:"+ str(float(SwapN)))
	#<--------  Swap   ---------------<
	
	#> ------ usuarios ----------------->
	nclientes=0
	for line in fileinput.input('/proc/net/tcp'):
		if re.search(octstr,line) :
			nclientes=nclientes+1
	fileinput.close()
	
	Usuarios=float(nclientes)
	UsuariosMax=float(int(configuracion.maxclientes))
	UsuariosN=(UsuariosMax-Usuarios)/UsuariosMax
	print """----Usuarios,UsuariosMax,UsuariosN------"""
	print Usuarios,UsuariosMax,UsuariosN
	syslog(LOG_DEBUG,"Parsea_proc --  Valor UsuariosN:"+ str(float(UsuariosN)))
	#< ------ usuarios -----------------<
	
	#> ------ ancho de banda utilizado y CPU instanataneo ---------------->

	for line in fileinput.input('/proc/net/dev'):
		if re.search("(eth0)",line) :
			eth=patron.split(line)
			syslog(LOG_DEBUG,"Parsea_proc -- /proc/net/dev 0 :"+ str(eth))
			print "eth" + str(eth)
	fileinput.close()
	
	
	ncpu=0
	for line in fileinput.input('/proc/stat'):
		if re.search("(cpu)",line) :
			cpu=string.split(line)
			syslog(LOG_DEBUG,"Parsea_proc -- /proc/stat 0 :"+ str(cpu))
		if re.search("cpu",line) :
			ncpu=ncpu+1
	fileinput.close()

	# sleep de un segundo para calcular bytes transmitidos por segundo y cpu instantaneo
	time.sleep(1)

	for line in fileinput.input('/proc/stat'):
		if re.search("(cpu)",line) :
			cpu1=string.split(line)
			syslog(LOG_DEBUG,"Parsea_proc -- /proc/stat 1 :"+ str(cpu1))
	fileinput.close()

	for line in fileinput.input('/proc/net/dev'):
		if re.search("(eth0)",line) :
			eth1=patron.split(line)
			syslog(LOG_DEBUG,"Parsea_proc -- /proc/net/dev 1 :"+ str(eth1))
	fileinput.close()
	
	REDn= 1 - ((float(eth1[2])+float(eth1[10])-float(eth[2])-float(eth[10]))/int(configuracion.redbw))
	syslog(LOG_DEBUG,"Parsea_proc --  Valor red:"+ str(float(REDn)))


	CPUn=float((float(cpu1[4])-float(cpu[4]))/(float(cpu1[1])-float(cpu[1])+float(cpu1[2])-float(cpu[2])+float(cpu1[3])-float(cpu[3])+float(cpu1[4])-float(cpu[4])+float(cpu1[5])-float(cpu[5])+float(cpu1[6])-float(cpu[6])+float(cpu1[7])-float(cpu[7])))
	syslog(LOG_DEBUG,"Parsea_proc --  Valor cpu:"+ str(float(CPUn)))
	#< ------ ancho de banda utilizado y CPU instanataneo ----------------<

	#> ------  CPU promedio ---------------->
	
	CPUHn=float(float(cpu1[4])/(float(cpu1[1])+float(cpu1[2])+float(cpu1[3])+float(cpu1[4])+float(cpu1[5])+float(cpu1[6])+float(cpu1[7])))
	syslog(LOG_DEBUG,"Parsea_proc --  Valor Cpuh:"+ str(float(CPUHn)))

	ncpu=ncpu-1

	for line in fileinput.input('/proc/loadavg'):
		loadavg=string.split(line)
	fileinput.close()

	CPUAVGn=float((int(configuracion.cpupower)*float(configuracion.maxavg)*float(ncpu)-float(loadavg[0]))/(int(configuracion.cpupower)*float(configuracion.maxavg)*float(ncpu)))
	syslog(LOG_DEBUG,"Parsea_proc --  Valor Avg:"+ str(float(CPUAVGn)))
	#< ------ CPU promedio ----------------<
	
	return [MemN,SwapN,CPUn,CPUHn,CPUAVGn,REDn,UsuariosN]
# ---------------------------------------
# o Este Algoritmo realiza Round Robin ponderado dinamicamente
# segun la carga del equipo. Los parametros de carga normalizados
# son obtenidos desde una Tupla entregada por la funcion parsea_proc
# dichos parametros son:'[MemN,SwapN,CPUn,CPUHn,CPUAVGn,REDn,UsuariosN]'.
# 
# o El valor Historico de uso del CPU (CPUHn) no es utilizado.
#
# o  Cuando todos los valores de esta Tupla son mayores a cero el estado
# es calculado de la siguiente manera:
# 
# 		**Estado=MEMn . SWnCPUn . CPUAVGn . REDn . USUARIOSn**.
#
# 		Como se puede observar es un producto de valores de carga
# normalizados , de manera que si un valor se aproxima a cero el estado
# rapidamente converge a cero.
#
# o Cuando alguno de los valores es menor o igual a 0 el estado es calculado de
# la siguiente manera:
#
# 		**Estado = -math.exp(-MEMn) . math.exp(-SWn) . math.exp(-CPUn) . math.exp(-CPUAVGn) . math.exp(-REDn) . math.exp(-USUARIOSn)**.
#
# o El valor devuelto por este algoritmo es llamado Disponibilidad Porcentual del servidor 
#  y se encuentra escalado por un factor ingresado en el archivo de configuracion (Defaulf=1):
#
#		**Disp_Porcentual=Estado . float(configuracion.algoritmo_escalar)**
# 
def algoritmo2():
	"""Algoritmo2: Roud Robin con pesos dinamicos. Productos positivos y exponenciales negativas """
	parsea_proc_result=parsea_proc()
	MEMn=parsea_proc_result[0]
	SWn=parsea_proc_result[1]
	CPUn=parsea_proc_result[2]
	CPUAVGn=parsea_proc_result[3]
	REDn=parsea_proc_result[5]
	USUARIOSn=parsea_proc_result[6]
	print """---------------------------------------------------------------------"""
	print """MEMn,SWn,CPUn,CPUAVGn,REDn,USUARIOSn"""
	print MEMn,SWn,CPUn,CPUAVGn,REDn,USUARIOSn
	if MEMn <=0 or SWn <=0 or  CPUn <=0 or CPUAVGn <=0 or  REDn <=0 or  USUARIOSn <=0 :
		Estado = - math.exp(-MEMn) * math.exp(-SWn) * math.exp(-CPUn) * math.exp(-CPUAVGn)* math.exp(-REDn) * math.exp(-USUARIOSn)
	else:
		Estado= MEMn*SWn*CPUn*CPUAVGn*REDn*USUARIOSn*(float(configuracion.cpupower))
	Disp_Porcentual=Estado*float(configuracion.algoritmo_escalar)
	print  'algoritmo2:  ' + str(Disp_Porcentual)
	syslog(LOG_DEBUG,"algoritmo2 --  Valor Disp_Porcentual:"+ str(float(Disp_Porcentual)))
	return Disp_Porcentual

# ---------------------------------------
# o Este Algoritmo realiza Round Robin ponderado dinamicamente segun la carga del equipo. Los parametros de carga normalizados son obtenidos desde una Tupla entregada por la funcion parsea_proc dichos parametros son:
# '[MemN,SwapN,CPUn,CPUHn,CPUAVGn,REDn,UsuariosN]'.
#
# o Cuando alguno de los valores es menor que 0 lo reeplaza por 0.1
#
# o Utiliza todos los valores para calcular el estado del servidor mediante la siguiente ecuacion:
# 
# 'estado=float((7 . int(configuracion.pesoserver))/(1/(valormem . int(configuracion.pesomem))+ 1/(valorswap . int(configuracion.pesoswap)) + 1/(valorcpu . int(configuracion.pesocpu)) + 1/(valorcpuh . int(configuracion.pesocpuh)) + 1/(valoravg . int(configuracion.pesoavg)) + 1/(valorred . int(configuracion.pesored)) + 1/(valorclientes . int(configuracion.pesoclientes))))'
#
def algoritmo3():
	"""Algoritmo3: Round Robin con pesos dinamicos. Suma de valores inversas"""
	parsea_proc_result=parsea_proc()
	valormem=parsea_proc_result[0]
	valorswap=parsea_proc_result[1]
	valorcpu=parsea_proc_result[2]
	valorcpuh=parsea_proc_result[3]
	valoravg=parsea_proc_result[4]
	valorred=parsea_proc_result[5]
	valorclientes=parsea_proc_result[6]
	print valormem,valorswap,valorcpu,valorcpuh,valoravg,valorred,valorclientes
	if valormem <= 0 :
		valormem=0.0001
		syslog(LOG_DEBUG," algoritmo1--  Trunca Valor mem:"+ str(float(valormem)))		 
	if valorswap <= 0 :
		valorswap=0.0001
		syslog(LOG_DEBUG," algoritmo1--  Trunca Valor swap:"+ str(float(valorswap)))		 
	
	if valorclientes <= 0 :
		valorclientes=0.0001
		syslog(LOG_DEBUG,"Parsea_proc --  Trunca Valor clientes:"+ str(float(valorclientes)))
	if valorcpu <= 0 :
		valorcpu=0.0001
		syslog(LOG_DEBUG,"Parsea_proc --  Trunca Valor cpu:"+ str(float(valorcpu)))		 
	if valorred <= 0 :
		valorred=0.0001
		syslog(LOG_DEBUG,"Parsea_proc --  Trunca Valor Red:"+ str(float(valorred)))		 
	if valorcpuh <= 0 :
		valorcpuh=0.0001
		syslog(LOG_DEBUG,"Parsea_proc --  Trunca Valor cpuh:"+ str(float(valorcpuh)))		 
	if valoravg <= 0 :
		valoravg=0.0001
		syslog(LOG_DEBUG,"Parsea_proc --  Trunca Valor Avg:"+ str(float(valoravg)))
	
	try :
		estado=float((7*int(configuracion.pesoserver))/(1/(valormem*int(configuracion.pesomem))+ 1/(valorswap*int(configuracion.pesoswap)) + 1/(valorcpu*int(configuracion.pesocpu)) + 1/(valorcpuh*int(configuracion.pesocpuh)) + 1/(valoravg*int(configuracion.pesoavg)) + 1/(valorred*int(configuracion.pesored)) + 1/(valorclientes*int(configuracion.pesoclientes))))
		syslog(LOG_DEBUG,"Parsea_proc --  Valor Mem:"+ str(float(valormem))+ " Valor Swap:" + str(float(valorswap))+ " Valor Cpu:" + str(float( valorcpu))+ " Valor Cpuh:"+ str(float( valorcpuh))+" Valor Avg:"+ str(float( valoravg))+" Valor Red:"+ str(float( valorred))+" Valor Clientes:"+ str(float( valorclientes)))
	except Exception ,detail:
		syslog(LOG_DEBUG,"Parsea_proc -- Ecepcion Error Calculo Carga : " + str(detail))
		valorcarga=0
	print  'algoritmo1:  ' + str(estado)
	syslog(LOG_DEBUG,"algoritmo1 --  Valor estado:"+ str(float(estado)))
	return estado

def algoritmo1():
    """Algoritmo1: Roud Robin con pesos estaticos."""
    Disp_Porcentual=float(configuracion.cpupower)*float(configuracion.algoritmo_escalar)
    print  'algoritmo3:' + str(Disp_Porcentual)
    syslog(LOG_DEBUG,"algoritmo3 --  Valor Disp_Porcentual:"+ str(float(Disp_Porcentual)))
    return Disp_Porcentual

##########################################################################################################################
#
#			Main  main MAIN
#			    
##########################################################################################################################
def terminar_programa(signum, frame):
	global socket_servidor
	global net 
	global netcliente
	print 'Signal handler called with signal', signum
	syslog(LOG_ERR,"terminar_programa --  Recibio una senial signum: " + str(signum))
	try:
		socket_servidor.close()
	except Exception, detail :
		syslog(LOG_ERR,"terminar_programa --  Excepcion socket_servidor.close() " + str(detail))
	try:
		net.termina()
	except Exception, detail :
		syslog(LOG_ERR,"Main --  Excepcion net.termina(): " + str(detail))
	try:
		netcliente.termina()
	except Exception, detail :
		syslog(LOG_ERR,"Main --  Excepcion netcliente.termina(): " + str(detail))
try:
	opts, args = getopt.getopt(sys.argv[1:], "c:p:d:vh",["config=","pid=","version","help"])
except getopt.GetoptError, (msg, opt):
	print sys.argv[0] + ": " + msg
	print "Proba '" + sys.argv[0] + " --help' para mas info."
	sys.exit(3)
for option,value in opts:
	if option in ("-c","--config"):
		arch_conf = value
	elif option in ("-p","--pid"):
		arch_pid=value
		try:
			fh = open(arch_pid,"w")
			fh.write(str(os.getpid()))
			fh.close()
		except:
			print "Imposible guardar archivo PID - Sale."
			sys.exit(2)

	elif option in ("-v","--version"):
		print "Protocolo de Reparto de Carga - ProRC \nVersion 0 Revision 4\n"
		sys.exit(3)
	elif option in ("-h","--help"):
		print "Usar: " + sys.argv[0] + " [OPCION]"
		print "Protocolo de Reparto de Carga - ProRC \nVersion 0 Revision 4\n"
		print "-c, --config=ruta_archivo   Ruta completa al archivo de configuracion."
		print "-p, --pid=ruta_archivo      Ruta completa al archivo donde se guarda el PID."
		print "-d, --debug                 Mantiene la consola."
		print "-v, --version	   	   Muestra la version."
		print "-h, --help            	   Imprime la ayuda."
		sys.exit(3)

try:
	fh = open(arch_conf,"r")
	fh.close()
except	Exception, err :
	print "\n\nImposible abrir archivo de configuracion.\nError:", arch_conf , "Error :",err
	print "\n\n\nEjecute de nuevo el programa para crear una configuracion por defecto", arch_conf
	print "\n\n\n"
	crea_configuracion()
	sys.exit(2)

try:	
	 configuracion=Configuracion()
	 openlog(str(configuracion.log_nombre),configuracion.log_opt,configuracion.log_facility)
	 leer_configuracion()
	 configuracion.configurar(salida)
	 syslog(LOG_INFO,configuracion.mostrar())
	 setlogmask(int(configuracion.log_mascara))
	 #configuracion.mostrar()
	 locklista=threading.Lock()
	 intf = socket.gethostbyname(socket.gethostname())
	 syslog(LOG_INFO,"Yo soy : " + str(intf))
	 ListaHilos =[]
	 estado=Estado()
	 syslog(LOG_INFO,"Inicializando Servicios_check ... ")
	 serv=Servicios_chk()
	 syslog(LOG_INFO,"Inicializando Estadistica ... ")
	 regestadistica=Estadistica()
	 syslog(LOG_INFO,"Inicializando Carga_check ... ")
	 carg=Carga_chk()
	 syslog(LOG_INFO,"Inicializando Estado_net_cliente ... ")
	 netcliente=Estado_net_cliente()
	 ListaHilos.append(serv)
	 ListaHilos.append(carg)
	 ListaHilos.append(netcliente)
	 syslog(LOG_INFO,"Inicializando Lista_top ... ")
	 lista=Lista_top()
	 syslog(LOG_INFO,"Inicializando Estado_net ... ")
	 net=Estado_net()
	 #print configuracion.mostrar()
	 syslog(LOG_INFO,"Inicializando Servicios_check Start ... ")
	 serv.start()
	 syslog(LOG_INFO,"Inicializando Carga_check Start ... ")
	 carg.start()
	 syslog(LOG_INFO,"Inicializando Estado_net_cliente Start ... ")
	 netcliente.start()
	 syslog(LOG_INFO,"Inicializando Estado_net Start ... ")
	 net.start()
	 syslog(LOG_INFO,"Inicializando Lista_top Start ... ")
	 lista.start()
	 syslog(LOG_INFO,"Inicializando Servidor ... ")
	 
	 
	 socket_servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	 socket_servidor.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
	 #signal.signal(signal.SIGTERM, terminar_programa)
	 #time.sleep(float(configuracion.intervalo_lista) + float(configuracion.intervalo_envio))
	 try:
	 	socket_servidor.bind(('',int(configuracion.puerto_server)))
	 except Exception, detail :
	 	syslog(LOG_ERR,"Main --  Excepcion Primer intento de bind en el 1703: " + str(detail))
	 	socket_servidor.close()
	 	time.sleep(3)
	 	try:
	 		socket_servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	 		socket_servidor.bind(('',int(configuracion.puerto_server)))
	 	except Exception, detail :
	 		syslog(LOG_ERR,"Main --  Excepcion Segundo intento de bind en el 1703: " + str(detail))
	 		socket_servidor.close()
	 		sys.exit(1)
	 
	 time.sleep(1)
	 socket_servidor.listen(5)
	 
	
	 
	 try :
	 	lista_conectados=[]
	        while True :
	                 (sock,ap)=socket_servidor.accept()
	                 try :
	                     s=Servidor_net(sock,ap,sock)
	                     locklista.acquire()
	                     lista_conectados.append((ap,sock,s))
	                     locklista.release()
	                     s.start()
	 		     time.sleep(1)
	                 except Exception , detail :
	                     syslog(LOG_INFO,"Servidor -- Excepcion ServerSocket : " + str(detail))
	             	 syslog(LOG_DEBUG,"Servidor -- Lista de Conectados :" + str(lista_conectados))
	 	syslog(LOG_INFO,"Cerrando Socket_servidor ... ")
	        socket_servidor.close()
	 	syslog(LOG_INFO,"Cerrando Estado_net ... ")
	        net.termina()
	        syslog(LOG_INFO,"Cerrando Servicios_check ... ")
	 	serv.termina()
	 	syslog(LOG_INFO,"Cerrando Carga_check ... ")
	        carg.termina()
	 	syslog(LOG_INFO,"Cerrando Estado_net_cliente ... ")
	        netcliente.termina()
	 	for s in ListaHilos :
	                 s.termina()
	 	serv.join()
	        carg.join()
	        netcliente.join()
	        for s in ListaHilos :
	                 s.join()
	 	net.join()
	        lista.join()
	 	for l in  lista_conectados:
	                  l[2].join()
	 	closelog()
	 	
	 except Exception, detail :
	        syslog(LOG_INFO,"Cerrando Socket_servidor ... ")
	        socket_servidor.close()
	 	syslog(LOG_INFO,"Cerrando Estado_net ... ")
	        net.termina()
	        syslog(LOG_INFO,"Cerrando Servicios_check ... ")
	 	serv.termina()
	 	syslog(LOG_INFO,"Cerrando Carga_check ... ")
	        carg.termina()
	 	syslog(LOG_INFO,"Cerrando Estado_net_cliente ... ")
	        netcliente.termina()
	 	for s in ListaHilos :
	                 s.termina()
	 
	 	lista.join()
	 	net.join()
	        serv.join()
	        carg.join()
	        netcliente.join()
	        for s in ListaHilos :
	                 s.join()
	 	for l in  lista_conectados:
	                  l[2].join()
	 	syslog(LOG_INFO,"Excepcion en main: " + str(detail))
	 	closelog()
	 	sys.exit(1)
 
except Exception, detail :
	syslog(LOG_ERR,"Main --  Excepcion Try general: " + str(detail))
	 
